package editor.widgets;

import editor.Images;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * This class is a replacement for {@link JScrollPane}.
 *
 * @author Neil Dickson
 */
public class CustomScrollPane extends JComponent {
	private	Component			component;
	private	JPanel				panel;
	private	Rectangle			viewport;
	private	VerticalScrollbar	verticalScrollbar;
	private	HorizontalScrollbar	horizontalScrollbar;
	private	JPanel				spacer;
	private	boolean				mustHaveHorizontal;
	private	boolean				mustHaveVertical;
	private	boolean				cantHaveHorizontal;
	private	boolean				cantHaveVertical;

	public static final int		VERTICAL_SCROLLBAR_WIDTH	= 18;
	public static final int		HORIZONTAL_SCROLLBAR_HEIGHT	= 18;
	public static final int		RADIUS_1 = 6;
	public static final int		RADIUS_2 = 7;

	public static final int[]	CURVE = new int[]{3,4,5,6,6,7,7,7,7,7,7,7,7,6,6,5,4,3};

	public static final Color	BACKGROUND_COLOUR			= Color.WHITE;
	public static final Color	SCROLLBAR_COLOUR			= new Color(30,28,28);

	public static final int		TOP_BUTTON_HEIGHT			= Images.VSCROLL_BUTTON_TOP.getHeight(null);
	public static final int		BOTTOM_BUTTON_HEIGHT		= Images.VSCROLL_BUTTON_BOTTOM.getHeight(null);
	public static final int		LEFT_BUTTON_WIDTH			= Images.HSCROLL_BUTTON_LEFT.getWidth(null);
	public static final int		RIGHT_BUTTON_WIDTH			= Images.HSCROLL_BUTTON_RIGHT.getWidth(null);

	public static final int		SCROLL_RATE					= 8;
	public static final int		SCROLL_TIME_DELAY			= 100;

	public static final int		OUTSIDE_SECTION				= 0;
	public static final int		FIRST_BUTTON_SECTION		= 1;
	public static final int		FIRST_BG_SECTION			= 2;
	public static final int		SCROLLBAR_SECTION			= 3;
	public static final int		SECOND_BG_SECTION			= 4;
	public static final int		SECOND_BUTTON_SECTION		= 5;

	public static final Image	VSCROLL_BG_256				= Images.VSCROLL_BG.getScaledInstance(VERTICAL_SCROLLBAR_WIDTH,256,Image.SCALE_REPLICATE);
	public static final Image	VSCROLLBAR_BG_256			= Images.VSCROLLBAR_BG.getScaledInstance(VERTICAL_SCROLLBAR_WIDTH,256,Image.SCALE_REPLICATE);
	public static final Image	HSCROLL_BG_256				= Images.HSCROLL_BG.getScaledInstance(256,HORIZONTAL_SCROLLBAR_HEIGHT,Image.SCALE_REPLICATE);
	public static final Image	HSCROLLBAR_BG_256			= Images.HSCROLLBAR_BG.getScaledInstance(256,HORIZONTAL_SCROLLBAR_HEIGHT,Image.SCALE_REPLICATE);

	public static final int		SCROLLBAR_NEVER				= -1;
	public static final int		SCROLLBAR_AS_NEEDED			= 0;
	public static final int		SCROLLBAR_ALWAYS			= 1;

	static {
		// Ensure that the scaled images get loaded immediately
		while (VSCROLL_BG_256.getHeight(null)<256 || VSCROLLBAR_BG_256.getHeight(null)<256 || HSCROLL_BG_256.getWidth(null)<256 || HSCROLLBAR_BG_256.getWidth(null)<256 || VSCROLL_BG_256.getWidth(null)<VERTICAL_SCROLLBAR_WIDTH || VSCROLLBAR_BG_256.getWidth(null)<VERTICAL_SCROLLBAR_WIDTH || HSCROLL_BG_256.getHeight(null)<HORIZONTAL_SCROLLBAR_HEIGHT || HSCROLLBAR_BG_256.getHeight(null)<HORIZONTAL_SCROLLBAR_HEIGHT) {
			try {
				Thread.sleep(10);
			}
			catch (InterruptedException e) {
				// This exception doesn't matter
			}
		}
	}

	/**
	 * Creates a new CustomScrollPane containing the specified {@link Component}
	 * @param c the component to be initially contained in the CustomScrollPane
	 */
	public CustomScrollPane(Component c) {
		component = c;
		viewport = new Rectangle();
		verticalScrollbar = new VerticalScrollbar();
		horizontalScrollbar = new HorizontalScrollbar();
		mustHaveHorizontal = false;
		mustHaveVertical = false;
		cantHaveHorizontal = false;
		cantHaveVertical = false;
		panel = new JPanel(null);
		panel.add(component);
		panel.setBackground(BACKGROUND_COLOUR);
		spacer = new JPanel();
		spacer.setBackground(BACKGROUND_COLOUR);
		add(panel);
		add(spacer);
		add(verticalScrollbar);
		add(horizontalScrollbar);
		setComponentZOrder(panel,3);
		updateComponentSizes();
		component.addComponentListener(new ComponentAdapter(){
			public void componentResized(ComponentEvent e) {
				updateComponentSizes();
			}
		});
	}

	/**
	 * This is overridden so that components can be resized on all changes to the CustomScrollPane's size
	 * @param x
	 * @param y
	 * @param w
	 * @param h
	 */
	@Deprecated
	public void reshape(int x, int y, int w, int h) {
		boolean isResizing = w!=getWidth() || h!=getHeight();
		super.reshape(x, y, w, h);
		if (isResizing) {
			updateComponentSizes();
		}
	}

	private void updateComponentSizes() {
		Dimension dim = component.getMinimumSize();
		int width = getWidth();
		int height = getHeight();
		// Don't even bother if the scroll pane doesn't have size.
		if (width<=0 || height<=0) {
			return;
		}
		// If completely within scroll pane, no scrollbars needed
		if (dim.width<=getWidth() && dim.height<=getHeight() && !mustHaveVertical && !mustHaveHorizontal) {
			verticalScrollbar.setVisible(false);
			horizontalScrollbar.setVisible(false);
			spacer.setVisible(false);
		}
		// If horizontally within scroll pane, only vertical scrollbar needed
		else if (dim.width<=getWidth()-VERTICAL_SCROLLBAR_WIDTH && !mustHaveHorizontal) {
			if (!cantHaveVertical) {
				width -= VERTICAL_SCROLLBAR_WIDTH;
			}
			verticalScrollbar.setVisible(!cantHaveVertical);
			horizontalScrollbar.setVisible(false);
			spacer.setVisible(false);
		}
		// If vertically within scroll pane, only horizontal scrollbar needed
		else if (dim.height<=getHeight()-HORIZONTAL_SCROLLBAR_HEIGHT && !mustHaveVertical) {
			if (!cantHaveHorizontal) {
				height -= HORIZONTAL_SCROLLBAR_HEIGHT;
			}
			verticalScrollbar.setVisible(false);
			horizontalScrollbar.setVisible(!cantHaveHorizontal);
			spacer.setVisible(false);
		}
		// Else both scrollbars needed
		else {
			if (!cantHaveVertical) {
				width -= VERTICAL_SCROLLBAR_WIDTH;
			}
			if (!cantHaveHorizontal) {
				height -= HORIZONTAL_SCROLLBAR_HEIGHT;
			}
			verticalScrollbar.setVisible(!cantHaveVertical);
			horizontalScrollbar.setVisible(!cantHaveHorizontal);
			spacer.setVisible(!cantHaveVertical && !cantHaveHorizontal);
		}
		verticalScrollbar.setBounds(width,0,VERTICAL_SCROLLBAR_WIDTH,height);
		horizontalScrollbar.setBounds(0,height,width,HORIZONTAL_SCROLLBAR_HEIGHT);
		spacer.setBounds(width,height,VERTICAL_SCROLLBAR_WIDTH,HORIZONTAL_SCROLLBAR_HEIGHT);
		component.setSize(dim);
		viewport.setSize(width,height);
		viewport.x = Math.max(Math.min(viewport.x,component.getWidth()-viewport.width),0);
		viewport.y = Math.max(Math.min(viewport.y,component.getHeight()-viewport.height),0);
		component.setLocation(-viewport.x,-viewport.y);
		// NOTE: Setting the bounds of the panel should be last, because this is what Headers are notified on, and the other stuff should be updated already.
		panel.setBounds(0,0,width,height);
		repaint();
	}

	public Component getComponent() {
		return component;
	}

	public void scrollTo(int x,int y) {
		viewport.x = x;
		viewport.y = y;
		component.setLocation(-viewport.x,-viewport.y);
		repaint();
	}

	public void scrollToRectVisible(int x,int y,int width,int height) {
		x = Math.max(Math.min(x,component.getWidth()),0);
		y = Math.max(Math.min(y,component.getHeight()),0);
		width = Math.max(Math.min(width,component.getWidth()-x),0);
		height = Math.max(Math.min(height,component.getHeight()-y),0);
		boolean fitsXAtZero = x+width<viewport.width || viewport.width<=1;
		boolean changed = false;
		if (fitsXAtZero) {
			changed = viewport.x!=0;
			viewport.x = 0;
		}
		else if (x<viewport.x) {
			viewport.x = x;
			changed = true;
		}
		else if (x+width>viewport.x+viewport.width) {
			if (width<viewport.width) {
				viewport.x = x+width-viewport.width;
				changed = true;
			}
			else {
				viewport.x = x;
				changed = true;
			}
		}
		if (y<viewport.y) {
			viewport.y = y;
			changed = true;
		}
		else if (y+height>viewport.y+viewport.height) {
			if (height<viewport.height) {
				viewport.y = y+height-viewport.height;
				changed = true;
			}
			else {
				viewport.y = y;
				changed = true;
			}
		}
		if (changed) {
			scrollTo(viewport.x,viewport.y);
		}
	}

	public Rectangle getViewport() {
		return viewport;
	}

	/**
	 * Sets the policy on when the horizontal scrollbar should be shown.
	 * @param policy allowed values are {@link #SCROLLBAR_ALWAYS}, {@link #SCROLLBAR_NEVER}, and {@link #SCROLLBAR_AS_NEEDED}
	 */
	public void setHorizontalScrollbarPolicy(int policy) {
		mustHaveHorizontal = policy==SCROLLBAR_ALWAYS;
		cantHaveHorizontal = policy==SCROLLBAR_NEVER;
	}

	/**
	 * Sets the policy on when the vertical scrollbar should be shown.
	 * @param policy allowed values are {@link #SCROLLBAR_ALWAYS}, {@link #SCROLLBAR_NEVER}, and {@link #SCROLLBAR_AS_NEEDED}
	 */
	public void setVerticalScrollbarPolicy(int policy) {
		mustHaveVertical = policy==SCROLLBAR_ALWAYS;
		cantHaveVertical = policy==SCROLLBAR_NEVER;
	}

	public class VerticalScrollbar extends JComponent implements MouseMotionListener, MouseWheelListener, MouseListener {
		private	Point	lastMouseMovedPoint;
		private	int		lastMouseMovedScrollbarY;
		private	Timer	scrollTimer;

		public VerticalScrollbar() {
			addMouseMotionListener(this);
			CustomScrollPane.this.addMouseWheelListener(this);
			addMouseListener(this);
		}
		public void paintComponent(Graphics g) {
			g.setColor(SCROLLBAR_COLOUR);
			g.fillRect(0,0,VERTICAL_SCROLLBAR_WIDTH,TOP_BUTTON_HEIGHT);
			g.drawImage(Images.VSCROLL_BUTTON_TOP,0,0,null);
			g.fillRect(0,getHeight()-BOTTOM_BUTTON_HEIGHT,VERTICAL_SCROLLBAR_WIDTH,BOTTOM_BUTTON_HEIGHT);
			g.drawImage(Images.VSCROLL_BUTTON_BOTTOM,0,getHeight()-BOTTOM_BUTTON_HEIGHT,null);
			int middleHeight = getMiddleHeight();
			int i;
			for (i=TOP_BUTTON_HEIGHT;i+255 < TOP_BUTTON_HEIGHT+middleHeight;i+=256) {
				g.drawImage(VSCROLL_BG_256,0,i,null);
			}
			g.drawImage(VSCROLL_BG_256,0,i,VERTICAL_SCROLLBAR_WIDTH,middleHeight&0xFF,null);
			int scrollbarHeight = getScrollbarHeight();
			int scrollbarY = getScrollbarY();
			Graphics2D g2 = (Graphics2D)g;
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
			g.fillRoundRect(0,scrollbarY-RADIUS_2,VERTICAL_SCROLLBAR_WIDTH,scrollbarHeight+RADIUS_2+RADIUS_2,RADIUS_1+RADIUS_1,RADIUS_2+RADIUS_2);
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
			g.drawImage(Images.VSCROLLBAR_TOP,0,scrollbarY-RADIUS_2,null);
			g.drawImage(Images.VSCROLLBAR_TOP,0,scrollbarY-RADIUS_2,null);
			for (i=scrollbarY;i+255 < scrollbarY+scrollbarHeight;i+=256) {
				g.drawImage(VSCROLLBAR_BG_256,0,i,null);
				g.drawImage(VSCROLLBAR_BG_256,0,i,null);
			}
			g.drawImage(VSCROLLBAR_BG_256,0,i,VERTICAL_SCROLLBAR_WIDTH,scrollbarHeight&0xFF,null);
			g.drawImage(VSCROLLBAR_BG_256,0,i,VERTICAL_SCROLLBAR_WIDTH,scrollbarHeight&0xFF,null);
			g.drawImage(Images.VSCROLLBAR_BOTTOM,0,scrollbarY+scrollbarHeight,null);
			g.drawImage(Images.VSCROLLBAR_BOTTOM,0,scrollbarY+scrollbarHeight,null);
		}

		public void mouseDragged(MouseEvent e) {
			if (lastMouseMovedPoint!=null) {
				int newScrollbarY = Math.max(Math.min(lastMouseMovedScrollbarY+(e.getY()-lastMouseMovedPoint.y), getHeight()-BOTTOM_BUTTON_HEIGHT-getScrollbarHeight()),TOP_BUTTON_HEIGHT);
				scrollTo(viewport.x,(newScrollbarY-TOP_BUTTON_HEIGHT)*component.getHeight()/getMiddleHeight());
			}
		}

		public void mouseMoved(MouseEvent e) {}

		public int getMiddleHeight() {
			return getHeight()-TOP_BUTTON_HEIGHT-BOTTOM_BUTTON_HEIGHT;
		}
		public int getScrollbarY() {
			return TOP_BUTTON_HEIGHT+viewport.y*getMiddleHeight()/component.getHeight();
		}
		public int getScrollbarHeight() {
			// This equation is derived from that component.getHeight()/viewport.height == middleHeight/scrollbarHeight
			return Math.min(viewport.height*getMiddleHeight()/component.getHeight(),getMiddleHeight());
		}

		public void mouseWheelMoved(MouseWheelEvent e) {
			scrollUnits(e.getUnitsToScroll());
		}
		public void scrollUnits(int units) {
			int newViewportY = Math.max(Math.min(viewport.y+units*SCROLL_RATE,component.getHeight()-viewport.height),0);
			scrollTo(viewport.x,newViewportY);
		}
		public void scrollPages(int pages) {
			int newViewportY = Math.max(Math.min(viewport.y+pages*viewport.height,component.getHeight()-viewport.height),0);
			scrollTo(viewport.x,newViewportY);
		}

		public int getPointSection(Point p) {
			if (p.x<0 || p.x>=VERTICAL_SCROLLBAR_WIDTH || p.y<RADIUS_2-CURVE[p.x]) {
				return OUTSIDE_SECTION;
			}
			if (p.y<TOP_BUTTON_HEIGHT-CURVE[p.x]) {
				return FIRST_BUTTON_SECTION;
			}
			if (p.y<getScrollbarY()-CURVE[p.x]) {
				return FIRST_BG_SECTION;
			}
			if (p.y<getScrollbarY()+getScrollbarHeight()+CURVE[p.x]) {
				return SCROLLBAR_SECTION;
			}
			if (p.y<TOP_BUTTON_HEIGHT+getMiddleHeight()+CURVE[p.x]) {
				return SECOND_BG_SECTION;
			}
			if (p.y<getHeight()-RADIUS_2+CURVE[p.x]) {
				return SECOND_BUTTON_SECTION;
			}
			return OUTSIDE_SECTION;
		}

		public void mouseClicked(MouseEvent e) {}
		public void mousePressed(MouseEvent e) {
			final Point pt = e.getPoint();
			int section = getPointSection(pt);
			if (section==FIRST_BUTTON_SECTION) {
				scrollUnits(-4);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						scrollUnits(-4);
					}
				});
				scrollTimer.start();
			}
			else if (section==FIRST_BG_SECTION) {
				scrollPages(-1);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						if (getPointSection(pt)==FIRST_BG_SECTION) {
							scrollPages(-1);
						}
					}
				});
				scrollTimer.start();
			}
			else if (section==SCROLLBAR_SECTION) {
				if (e.getButton()==MouseEvent.BUTTON1) {
					lastMouseMovedPoint = e.getPoint();
					lastMouseMovedScrollbarY = getScrollbarY();
				}
			}
			else if (section==SECOND_BG_SECTION) {
				scrollPages(1);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						if (getPointSection(pt)==SECOND_BG_SECTION) {
							scrollPages(1);
						}
					}
				});
				scrollTimer.start();
			}
			else if (section==SECOND_BUTTON_SECTION) {
				scrollUnits(4);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						scrollUnits(4);
					}
				});
				scrollTimer.start();
			}
		}
		public void mouseReleased(MouseEvent e) {
			if (e.getButton()==MouseEvent.BUTTON1) {
				lastMouseMovedPoint = null;
			}
			if (scrollTimer!=null) {
				scrollTimer.stop();
				scrollTimer = null;
			}
		}
		public void mouseEntered(MouseEvent e) {}
		public void mouseExited(MouseEvent e) {}
	}

	public class HorizontalScrollbar extends JComponent implements MouseMotionListener, MouseListener {
		private	Point	lastMouseMovedPoint;
		private	int		lastMouseMovedScrollbarX;
		private	Timer	scrollTimer;

		public HorizontalScrollbar() {
			addMouseMotionListener(this);
			addMouseListener(this);
		}
		public void paintComponent(Graphics g) {
			g.setColor(SCROLLBAR_COLOUR);
			g.fillRect(0,0,LEFT_BUTTON_WIDTH,HORIZONTAL_SCROLLBAR_HEIGHT);
			g.drawImage(Images.HSCROLL_BUTTON_LEFT,0,0,null);
			g.fillRect(getWidth()-RIGHT_BUTTON_WIDTH,0,RIGHT_BUTTON_WIDTH,HORIZONTAL_SCROLLBAR_HEIGHT);
			g.drawImage(Images.HSCROLL_BUTTON_RIGHT,getWidth()-RIGHT_BUTTON_WIDTH,0,null);
			int middleWidth = getMiddleWidth();
			for (int i=LEFT_BUTTON_WIDTH;i<LEFT_BUTTON_WIDTH+middleWidth;++i) {
				g.drawImage(Images.HSCROLL_BG,i,0,null);
			}
			int scrollbarWidth = getScrollbarWidth();
			int scrollbarX = getScrollbarX();
			Graphics2D g2 = (Graphics2D)g;
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
			g.fillRoundRect(scrollbarX-RADIUS_2,0,scrollbarWidth+RADIUS_2+RADIUS_2,HORIZONTAL_SCROLLBAR_HEIGHT,RADIUS_2+RADIUS_2,RADIUS_1+RADIUS_1);
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
			g.drawImage(Images.HSCROLLBAR_LEFT,scrollbarX-RADIUS_2,0,null);
			g.drawImage(Images.HSCROLLBAR_LEFT,scrollbarX-RADIUS_2,0,null);
			int i;
			for (i=scrollbarX;i+255 < scrollbarX+scrollbarWidth;i+=256) {
				g.drawImage(HSCROLLBAR_BG_256,i,0,null);
				g.drawImage(HSCROLLBAR_BG_256,i,0,null);
			}
			g.drawImage(HSCROLLBAR_BG_256,i,0,scrollbarWidth&0xFF,HORIZONTAL_SCROLLBAR_HEIGHT,null);
			g.drawImage(HSCROLLBAR_BG_256,i,0,scrollbarWidth&0xFF,HORIZONTAL_SCROLLBAR_HEIGHT,null);
			g.drawImage(Images.HSCROLLBAR_RIGHT,scrollbarX+scrollbarWidth,0,null);
			g.drawImage(Images.HSCROLLBAR_RIGHT,scrollbarX+scrollbarWidth,0,null);
		}

		public void mouseDragged(MouseEvent e) {
			if (lastMouseMovedPoint!=null) {
				int newScrollbarX = Math.max(Math.min(lastMouseMovedScrollbarX+(e.getX()-lastMouseMovedPoint.x), getWidth()-RIGHT_BUTTON_WIDTH-getScrollbarWidth()),LEFT_BUTTON_WIDTH);
				scrollTo((newScrollbarX-LEFT_BUTTON_WIDTH)*component.getWidth()/getMiddleWidth(),viewport.y);
			}
		}
		public int getMiddleWidth() {
			return getWidth()-LEFT_BUTTON_WIDTH-RIGHT_BUTTON_WIDTH;
		}
		public int getScrollbarWidth() {
			// This equation is derived from that component.getWidth()/viewport.width == middleWidth/scrollbarWidth
			return Math.min(viewport.width*getMiddleWidth()/component.getWidth(),getMiddleWidth());
		}
		public int getScrollbarX() {
			return LEFT_BUTTON_WIDTH+viewport.x*getMiddleWidth()/component.getWidth();
		}

		public void scrollUnits(int units) {
			int newViewportX = Math.max(Math.min(viewport.x+units*SCROLL_RATE,component.getWidth()-viewport.width),0);
			scrollTo(newViewportX,viewport.y);
		}
		public void scrollPages(int pages) {
			int newViewportX = Math.max(Math.min(viewport.x+pages*viewport.width,component.getWidth()-viewport.width),0);
			scrollTo(newViewportX,viewport.y);
		}

		public void mouseMoved(MouseEvent e) {}
		
		public int getPointSection(Point p) {
			if (p.y<0 || p.y>=HORIZONTAL_SCROLLBAR_HEIGHT || p.x<RADIUS_2-CURVE[p.y]) {
				return OUTSIDE_SECTION;
			}
			if (p.x<TOP_BUTTON_HEIGHT-CURVE[p.y]) {
				return FIRST_BUTTON_SECTION;
			}
			if (p.x<getScrollbarX()-CURVE[p.y]) {
				return FIRST_BG_SECTION;
			}
			if (p.x<getScrollbarX()+getScrollbarWidth()+CURVE[p.y]) {
				return SCROLLBAR_SECTION;
			}
			if (p.x<LEFT_BUTTON_WIDTH+getMiddleWidth()+CURVE[p.y]) {
				return SECOND_BG_SECTION;
			}
			if (p.x<getWidth()-RADIUS_2+CURVE[p.y]) {
				return SECOND_BUTTON_SECTION;
			}
			return OUTSIDE_SECTION;
		}
		public void mouseClicked(MouseEvent e) {}
		public void mousePressed(MouseEvent e) {
			final Point pt = e.getPoint();
			int section = getPointSection(pt);
			if (section==FIRST_BUTTON_SECTION) {
				scrollUnits(-4);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						scrollUnits(-4);
					}
				});
				scrollTimer.start();
			}
			else if (section==FIRST_BG_SECTION) {
				scrollPages(-1);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						if (getPointSection(pt)==FIRST_BG_SECTION) {
							scrollPages(-1);
						}
					}
				});
				scrollTimer.start();
			}
			else if (section==SCROLLBAR_SECTION) {
				if (e.getButton()==MouseEvent.BUTTON1) {
					lastMouseMovedPoint = e.getPoint();
					lastMouseMovedScrollbarX = getScrollbarX();
				}
			}
			else if (section==SECOND_BG_SECTION) {
				scrollPages(1);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						if (getPointSection(pt)==SECOND_BG_SECTION) {
							scrollPages(1);
						}
					}
				});
				scrollTimer.start();
			}
			else if (section==SECOND_BUTTON_SECTION) {
				scrollUnits(4);
				scrollTimer = new Timer(SCROLL_TIME_DELAY,new ActionListener(){
					public void actionPerformed(ActionEvent e) {
						scrollUnits(4);
					}
				});
				scrollTimer.start();
			}
		}
		public void mouseReleased(MouseEvent e) {
			if (e.getButton()==MouseEvent.BUTTON1) {
				lastMouseMovedPoint = null;
			}
			if (scrollTimer!=null) {
				scrollTimer.stop();
				scrollTimer = null;
			}
		}
		public void mouseEntered(MouseEvent e) {}
		public void mouseExited(MouseEvent e) {}
	}
}
